<?php

namespace app\common\library;

use think\Log;
use think\Env;
use think\Exception;
use app\admin\model\pt\Depart as DepartModel;
use app\admin\model\pt\Job as JobModel;
use app\admin\model\pt\Person as PersonModel;
use app\admin\model\pt\DutyList as DutyModel;
use app\admin\model\pt\Salary as SalaryModel;
use app\common\library\Salary as SalaryLib;
use Carbon\Carbon;


class Salary
{
    protected $_salaryModel = null;

    public function __construct()
    {
        $this->_salaryModel = new SalaryModel();
    }

    public function delSalary($personId, $dateId, $jobId)
    {
        // 删除未结算的
        $salaryInfo = $this->_salaryModel->where('pt_person_id', $personId) 
                                         ->where('date_id', $dateId)
                                         ->where('pt_job_id', $jobId)
                                         ->where('salary_total', 0)
                                         ->find();
        if ($salaryInfo) {
            $salaryInfo->delete();
        }
    }

    public function setObject($personInfo, $departInfo, $jobInfo, $salaryInfo = null)
    {
        $this->personInfo = $personInfo;
        $this->departInfo = $departInfo;
        $this->jobInfo = $jobInfo;
        $this->salaryInfo = $salaryInfo;
    }

    public function addSalary($dutyId, $dateId, $personId = 0, $jobId = 0, $departId = 0)
    {
        if (!empty($personId)) {
            $this->personInfo = PersonModel::get($personId);
        }
        if (!empty($jobId)) {
            $this->jobInfo = JobModel::get($jobId);
        }
        if (!empty($departId)) {
            $this->departInfo = DepartModel::get($departId);
        }
        $this->_addSalary($dutyId, $dateId);
    }

    public function checkSelfAndReward($dateId)
    {
        $res = [0, 0];
        //  检查当月有无计算过自招费用以及激励费用 
        $curMonth = date('Ym', strtotime($dateId));
        $checkRow = SalaryModel::where('pt_person_id', $this->personInfo->id)->where('date_id', 'like', $curMonth . '%')
                    ->where('self_sevice_fee', '>', 0)
                    ->find();
        if ($checkRow) {
            $res[0] = $checkRow->self_sevice_fee;
            $res[1] = $checkRow->reward_month;
        }
        $checkRow = SalaryModel::where('pt_person_id', $this->personInfo->id)->where('date_id', 'like', $curMonth . '%')
                    ->where('reward_month', '>', 0)
                    ->find();
        if ($checkRow) {
            $res[1] = $checkRow->reward_month;
        }

        return $res;
    }

    // 计算餐费规则
    // 餐补规则： 实际出勤时长<应出勤时长的65%，则餐费为0
    // 场次餐补填写啥返回啥
    public function checkAdde1Fee($calClock)
    {
        $added1Fee = $this->salaryInfo->added1_fee; 
        $requireDuration = $this->salaryInfo->require_duration;
        if (!empty($calClock['clock_in'])) {
            // 餐费的计薪标准
            $s = 65;
            $d = ceil($calClock['actual_duration'] / $requireDuration * 100);
            if ($d < $s) {
                $added1Fee = 0;
            }
        }

        return $added1Fee;
    }
    
    // 计算工资 
    public function calSalary($calClock, $salaryMode = '')
    {
        $salary = 0;
        $calSalary = $this->salaryInfo->salary;
        if (empty($salaryMode)) {
            $salaryMode = $this->salaryInfo->salary_mode;
        }
        if ($salaryMode == 'hour') {
            $salary = round($calSalary * $calClock['actual_calc_duration'], 2);
        }
        if ($salaryMode == 'day') {
            $salary = round($calSalary * $calClock['actual_calc_duration'], 2);
        }
        if ($salaryMode == 'stage') {
            $salaryRule = $this->salaryInfo->salary_rule;  
            // 加上当前场次后累积计算
            $personStages = $this->personInfo->explain_total + $calClock['actual_calc_duration'];
            // 非劳务公司计算
            if (!empty($salaryRule)) {
                $ruleJson = json_decode($salaryRule, true);
                foreach ($ruleJson as $rule) {
                    // 目前是两边都加上等于
                    $end = $rule['end'];
                    if (empty($end)) {
                        $end = 99999;
                    }
                    if ($personStages >= $rule['start'] && $personStages <= $end) {
                        $calSalary= $rule['salary'];
                        break;
                    }
                }
            }
            $salary = round($calSalary * $calClock['actual_calc_duration'], 2);
        }
        // 场次工资
        return [$salary, $calSalary];
    }
    
    // 计算打卡时间, 根据以下规则计算实际出勤时间和应计薪时长
    // 默认9点， 9点以前， 都算从9点算工资， 9点以后， 按后面实际时间计算开始
    /*
     * 第一次打卡时间=C1 最后一次打卡时间=C2
        应出勤时长=A
        应出计薪时长=B
        实际出勤时长=C2-C1=C
        实际计薪时长=C-(A-B)=D

        按小时工资时 = D * 小时工资
        按天工资：5：30后打卡，然后D>B 按一天工资，D<B, D/B计算比例后乘以一天工资

     */
    public function calClock($clockJson, $salaryMode, $duty = null)
    {
        $calRes = [
            'clock_in' => 0,
            'clock_out' => 0,
            'actual_duration' => 0,
            'actual_calc_duration' => 0,
        ];
        if (empty($salaryMode)) {
            $salaryMode = $this->salaryInfo->salary_mode;
        }
        // 应出勤时长 
        $requireDuration = $this->salaryInfo->require_duration;
        // 应计薪时长
        $requireCalcDuration = $this->salaryInfo->require_calc_duration;
        // 差值时长, 后面计算应计薪时长需要
        $diffDuration = $requireDuration - $requireCalcDuration;
        if (empty($requireCalcDuration)) {
            return $calRes;
        }
        
        // 将该时间换成设置的最早时间 
        $starttime = "09:00:00";
        if (!empty($this->salaryInfo->max_start)) {
            $starttime = $this->salaryInfo->max_start . ":00";
        }
        $endtime = "17:30:00";
        asort($clockJson);
        $clockIn = $clockJson[0];
        $clockOut = $clockJson[count($clockJson) - 1];
        $calRes['clock_in'] = $clockIn;
        $calRes['clock_out'] = $clockOut;
        $curDate = date('Y-m-d', $clockIn);
        
        // 应打卡开始时间
        $startClock = strtotime($curDate . " " . $starttime);
        // 应打卡结束时间 
        $endClock = strtotime($curDate . " " . $endtime);
        
        // 可用于计算的打卡开始时间 
        $calStartClock = $startClock;
        // 如果开始打卡大于定义的开始时间
        if ($clockIn > $startClock) {
            // 如果有设置抹零分钟数
            if (!empty($duty->ignore_mins)) {
                $ignoreSecs = $duty->ignore_mins * 60;
                // 抹零后的秒数
                $clockIn = $clockIn - $ignoreSecs;
                if ($clockIn > $startClock) {
                    $calStartClock = $clockIn;
                } else {
                    // 达到抹零要求时，将打卡开始时间改为最早打卡时间记录
                    $calRes['clock_in'] = $startClock;
                }
            } else {
                $calStartClock = $clockIn;
            }
        }
        // 可用于计算的打卡结束时间 
        $calEndClock = $clockOut;
        $startCarbon = Carbon::parse($calStartClock);
        $endCarbon = Carbon::parse($calEndClock);

        $diffHours = $endCarbon->diffInHours($startCarbon);
        $diffFloatHours = $endCarbon->floatDiffInHours($startCarbon);
        // 实际出勤时长, 保留2位，这样显示时能更清楚看到 
        $actualDuration = round($diffFloatHours, 2);
        $mins = ceil(($diffFloatHours - $diffHours) * 60);
        if ($mins > 30) {
            $diffHours = $diffHours + 0.5;
        }
        // 应计薪时长
        $actualCalcDuration = round($diffHours - $diffDuration, 1);
        // 如果是小时工资
        if ($salaryMode == 'hour') {
            $calRes['actual_duration'] = $actualDuration;
            $calRes['actual_calc_duration'] = $actualCalcDuration;
        }
        // 如果是按天计算工资 
        if ($salaryMode == 'day') {
            $calRes['actual_duration'] = $actualDuration;
            if ($actualCalcDuration >= $requireCalcDuration) {
                $calRes['actual_calc_duration'] = 1;
            } else {
                // 计算比例
                $calRes['actual_calc_duration'] = round($actualCalcDuration / $requireCalcDuration, 1);
            }
        }

        return $calRes;



    }

    public function calStage($clockJson)
    {
        $calRes = [
            'clock_in' => 0,
            'clock_out' => 0,
            'actual_duration' => 0,
            'actual_calc_duration' => 0,
        ];
        $salaryRule = $this->salaryInfo->salary_rule;  
        $personStages = $this->personInfo->explain_total;
        // 加上本次讲解场次后根据场次规则计算
        $calRes['actual_duration'] = $clockJson['stage'];
        $calRes['actual_calc_duration']= $clockJson['stage'];

        return $calRes;
    }

    private function _addSalary($dutyId, $dateId)
    {
        $params = [];
        $params['duty_id'] = $dutyId;
        $params['date_id'] = $dateId;
        $params['user_id'] = $this->personInfo->user_id;
        $params['pt_person_id'] = $this->personInfo->id;
        $params['pt_depart_id'] = $this->departInfo->id;
        $params['depart_name'] = $this->departInfo->name;
        $params['pt_job_id'] = $this->jobInfo->id;
        $params['job_name'] = $this->jobInfo->name;
        $params['salary_mode'] = $this->jobInfo->salary_mode;
        $params['max_start'] = $this->jobInfo->max_start;
        // 根据人员和岗位对比后填入
        $salaryInfo = $this->checkSalary();
        if (empty($salaryInfo['salary']) && empty($salaryInfo['salary_rule'])) {
            Log::write('没有获取到薪水规则信息, job  =>' . var_export($this->jobInfo->toArray(), true));
            return ;
        }
        $params['salary_rule'] = $salaryInfo['salary_rule'];
        $params['salary'] = $salaryInfo['salary'];

        // 餐费这里先快照进来，然后每天计算薪酬的脚本根据时长判断是否改为0
        $params['added1_fee'] = $this->jobInfo->added1_fee;
        $params['added2_fee'] = $this->jobInfo->added2_fee;
        $params['require_duration'] = $this->jobInfo->attendance_duration;
        $params['require_calc_duration'] = $this->jobInfo->calc_duration;
        $salaryInfo = $this->_salaryModel->where('pt_person_id', $this->personInfo->id)
                                         ->where('date_id', $dateId)
                                         ->find();
        if ($salaryInfo) {
            $params['id'] = $salaryInfo->id;
        } else {
            $salaryInfo = new SalaryModel();
        }

        $salaryInfo->save($params);
    }

    private function checkSalary()
    {
        $salaryInfo = [
            'salary'  => 0, 
            'salary_rule' => '',
        ];
        // 获取人员类别
        $personType = $this->personInfo->user_type; 
        $laborId = $this->personInfo->pt_labor_id;
        // 劳务公司
        if ($personType == 'labor') {
            // 判断劳务公司
            $jobInfo = $this->jobInfo->toArray();
            // 判断薪资模式
            switch($jobInfo['salary_mode']) {
                case 'hour':
                  $salaryInfo['salary'] = $jobInfo['labor' . $laborId . '_salary'];
                  break;
                case 'day':
                  $salaryInfo['salary'] = $jobInfo['labor' . $laborId . '_salary_day'];
                  break;
                case 'stage':
                  $salaryInfo['salary_rule'] = $jobInfo['labor' . $laborId .'_salary_stage'];
                  break;
            }
        } else {
            // 其他都算自招 根据薪资模式取值
            switch($this->jobInfo->salary_mode) {
                case 'hour':
                  $salaryInfo['salary'] = $this->jobInfo->self_salary;
                  break;
                case 'day':
                  $salaryInfo['salary'] = $this->jobInfo->self_salary_day;
                  break;
                case 'stage':
                  $salaryInfo['salary'] = $this->jobInfo->self_salary_stage;
                  break;
            }
        }

        return $salaryInfo;
    }


}
